type Type =
  | 'string'
  | 'bigint'
  | 'number'
  | 'undefined'
  | 'object'
  | 'null'
  | 'array'
  | 'boolean'
  | 'symbol'
  | 'function'
  | 'NaN'

export const isNull = (val: any): boolean => {
  return val === null
}

export const isNaN = (val: any) => {
  return Number.isNaN(val)
}

export const isUndefined = (val: any) => {
  return typeof val === 'undefined'
}

export const isNumber = (val: any): boolean => {
  ;(Number.prototype as any).__type__ = 'number'
  return val.__type__ === 'number'
}

export const isString = (val: any): boolean => {
  ;(String.prototype as any).__type__ = 'string'
  return val.__type__ === 'string'
}

export const isObj = (val: any): boolean => {
  ;(Object.prototype as any).__type__ = 'object'
  return val.__type__ === 'object'
}

export const isArray = (val: any): boolean => {
  ;(Array.prototype as any).__type__ = 'array'
  return val.__type__ === 'array'
}

export const isFunction = (val: any): boolean => {
  ;(Function.prototype as any).__type__ = 'function'
  return val.__type__ === 'function'
}

export const isDate = (val: any) => {
  ;(Date.prototype as any).__type__ = 'date'
  return val.__type__ === 'date'
}

export const isSymbol = (val: any) => {
  ;(Symbol.prototype as any).__type__ = 'symbol'
  return val.__type__ === 'symbol'
}

export const isBool = (val: any) => {
  ;(Boolean.prototype as any).__type__ = 'boolean'
  return val.__type__ === 'boolean'
}

export const isBigInt = (val: any) => {
  ;(BigInt.prototype as any).__type__ = 'bigint'
  return val.__type__ === 'bigint'
}

export const getType = (val: any): Type => {
  if (isNull(val)) {
    return 'null'
  }
  if (isUndefined(val)) {
    return 'undefined'
  }
  ;(Number.prototype as any).__type__ = 'number'
  ;(String.prototype as any).__type__ = 'string'
  ;(Object.prototype as any).__type__ = 'object'
  ;(Array.prototype as any).__type__ = 'array'
  ;(Function.prototype as any).__type__ = 'function'
  ;(Date.prototype as any).__type__ = 'date'
  ;(Symbol.prototype as any).__type__ = 'symbol'
  ;(Boolean.prototype as any).__type__ = 'boolean'
  ;(BigInt.prototype as any).__type__ = 'bigint'
  const valType = val.__type__
  if (valType === 'number' && isNaN(val)) {
    return 'NaN'
  }
  return valType
}
export const useType = () => {
  return {
    isNull,
    isNaN,
    isUndefined,
    isArray,
    isBigInt,
    isBool,
    isDate,
    isFunction,
    isObj,
    isString,
    getType
  }
}
